package com.rc.evcharger.service;

import com.alibaba.fastjson.JSON;
import com.github.dozermapper.core.Mapper;
import com.rc.evcharger.biz.log.ChargedProcessLogAssemble;
import com.rc.evcharger.biz.notify.NotifyStartChargeResult;
import com.rc.evcharger.biz.notify.NotifyStopChargeResult;
import com.rc.evcharger.biz.notify.NotiyStationsStatus;
import com.rc.evcharger.common.config.MqCommandConfig;
import com.rc.evcharger.common.constant.SocketConstant;
import com.rc.evcharger.common.constant.WebConstant;
import com.rc.evcharger.common.dto.CalcalateResultDto;
import com.rc.evcharger.common.dto.CalculateDto;
import com.rc.evcharger.common.dto.ChargeBalaceDto;
import com.rc.evcharger.common.enums.ChargePhaseEnum;
import com.rc.evcharger.common.enums.ElecPileStopReasonEnum;
import com.rc.evcharger.common.enums.HlhtOrderStatusEnum;
import com.rc.evcharger.common.enums.SynEnum;
import com.rc.evcharger.common.mq.MqProducer;
import com.rc.evcharger.common.terminal.*;
import com.rc.evcharger.common.terminal.ChargeControlResult;
import com.rc.evcharger.common.utils.DateHelper;
import com.rc.evcharger.component.SynExcution;
import com.rc.evcharger.model.elec.ElecGun;
import com.rc.evcharger.model.elec.ElecPile;
import com.rc.evcharger.model.elec.ElecPilePower;
import com.rc.evcharger.model.elec.ElecStationPrice;
import com.rc.evcharger.model.member.MemberInfo;
import com.rc.evcharger.model.order.OrderComment;
import com.rc.evcharger.model.order.OrderDelayPush;
import com.rc.evcharger.model.order.OrderInfo;
import com.rc.evcharger.redis.RedChargeDataService;
import com.rc.evcharger.redis.RedPileService;
import com.rc.evcharger.redis.RedisService;
import com.rc.evcharger.service.elec.*;
import com.rc.evcharger.service.handle.ChargeHandler;
import com.rc.evcharger.service.handle.ChargePriceHandler;
import com.rc.evcharger.service.hlht.HlhtTenantOpenPriceService;
import com.rc.evcharger.service.member.MemberInfoService;
import com.rc.evcharger.service.order.OrderCommentService;
import com.rc.evcharger.service.order.OrderDelayPushService;
import com.rc.evcharger.service.order.OrderDetailService;
import com.rc.evcharger.service.order.OrderInfoService;
import com.rc.evcharger.service.tenant.TenantSettingService;
import com.rc.evcharger.vo.charge.ChargeBalaceRet;
import com.rc.evcharger.vo.charge.ChargeControlRet;
import com.rc.evcharger.vo.charge.ChargeReportRet;
import com.rc.evcharger.dto.msg.TerminalMessage;
import com.rc.evcharger.dto.terminal.ChargeBalaceResult;
import com.rc.evcharger.dto.terminal.ChargeReportResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * Create by Yang on 2020/3/16
 */
@Service
public class ChargeMessageServiceImpl implements ChargeMessageService {
    private static Logger logger = LoggerFactory.getLogger(ChargeMessageServiceImpl.class);

    //最低停止充电金额
    //private final BigDecimal STOP_CHARGING_LIMIT = new BigDecimal("1");
    //private CarVinUtil carVinUtil = CarVinUtil.newInstance();

    @Autowired
    private Mapper dozerMapper;

    @Autowired
    private MqProducer mqProducer;

    @Autowired
    private NotifyStartChargeResult notifyStartChargeResult;

    @Autowired
    private NotifyStopChargeResult notifyStopChargeResult;

    @Autowired
    private NotiyStationsStatus notiyStationsStatus;

    @Autowired
    private ElecPileService elecPileService;

    @Autowired
    private ElecPileOfflineService elecPileOfflineService;

    @Autowired
    private ElecGunService elecGunService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private OrderInfoService orderInfoService;

    @Autowired
    private OrderCostService orderCostService;

    @Autowired
    private RedChargeDataService redChargeDataService;

    @Autowired
    private MemberInfoService memberInfoService;

    @Autowired
    private RedPileService redPileService;

    @Autowired
    private ElecStationPriceService elecStationPriceService;

    @Autowired
    private ElecStationService elecStationService;

    @Autowired
    private OrderDetailService orderDetailService;

    @Autowired
    private OrderCommentService orderCommentService;

    @Autowired
    private ChargedProcessLogAssemble chargedProcessLogAssemble;

    @Autowired
    private OrderDelayPushService orderDelayPushService;

    @Autowired
    private TenantSettingService tenantSettingService;

    @Autowired
    private SynExcution synExcution;

    @Autowired
    private HlhtTenantOpenPriceService hlhtTenantOpenPriceService;

    @Autowired
    private ChargeHandler chargeHandler;

    @Autowired
    private ChargePriceHandler chargePriceHandler;

    @Autowired
    private MqCommandConfig mqCommandConfig;

    @Autowired
    private ElecPileHostService elecPileHostService;
    @Autowired
    private ElecPilePowerService elecPilePowerService;

    @Override
    public void login(ElecPile elecPile) {
        try {
            //如果电桩登录之前是离线状态，则保存离线记录
            //桩状态,0: 离网；1: 空闲；2: 占用（未充电）；3: 占用（充电中）；4: 占用（预约锁定）；255: 故障 默认1
            if (elecPile.getStatus().equals(SocketConstant.OFF_LINE)) {
                elecPileOfflineService.addPileOffline(elecPile.getElecPileId(), elecPile.getLogoutTime(), new Date(), Integer.valueOf(SocketConstant.OFF_LINE));
            }

            //更新充电桩状态为在线
            ElecPile newElecPile = new ElecPile();
            newElecPile.setElecPileId(elecPile.getElecPileId());
            newElecPile.setStatus(Integer.valueOf(SocketConstant.ON_LINE));
            newElecPile.setElecOffOnline(String.valueOf(SocketConstant.ON_LINE));   //更新强制状态
            elecPileService.updateByPrimaryKeySelective(newElecPile);

            //更新桩通讯地址
            //elecPileHostService.updateHostByElecPileId(elecPile.getElecPileId());
            //推送电桩状态
            notiyStationsStatus.notifyPileStatus(elecPile);
        } catch (Exception e) {
            logger.error("login方法解析出错,对应的电桩ID为:" + elecPile.getPileRtua(), e);
        }
    }

    @Override
    public void loginOut(ElecPile elecPile) {
        try {
            //更新充电桩状态为离线
            elecPile.setStatus(Integer.valueOf(SocketConstant.OFF_LINE));
            //记录最后一次登出时间
            elecPile.setLogoutTime(new Date());
            elecPileService.updateByPrimaryKeySelective(elecPile);

            //推送电桩状态
            notiyStationsStatus.notifyPileStatus(elecPile);
        } catch (Exception e) {
            logger.error("loginOut方法解析出错,对应的电桩ID为:" + elecPile.getPileRtua(), e);
        }
    }

    @Override
    public void hearBeat(ElecPile pile, TerminalMessage msg) {
        Result result = new HearBeat();
        //logger.info("3心跳数据项,对应桩编号:{}，对应data:{}", pile.getPileNo(), msg.getBody());
        List<HearBeat> resList = null;
        try {
            resList = result.getResult(msg.getData());
        } catch (StringIndexOutOfBoundsException e) {
            logger.error("心跳报文解析报错,对应桩编号：{},对应心跳报文data:{}", pile.getPileNo(), msg.getData());
            e.printStackTrace();
            return;
        }
        HearBeatListResult hearBeatResult = new HearBeatListResult(pile.getElecPileId(), resList);

        try {
            for (HearBeat hearBeat : hearBeatResult.getHearBeats()) {
                ElecGun elecGun = elecGunService.validGun(pile, hearBeat.getGunNum());

                // 把故障存入redis中;
                if (elecGun != null) {
                    // 连接状态: 1.插枪，2.未插枪
                    // 枪状态：1、空闲,2、充电，3、故障 4.枪锁故障。

                    //原枪normal:是否正常0：故障，1：正常
                    //原枪using_status 使用状态0：空闲，1：使用中
                    //转为：
                    //枪normal_status:是否正常 0：正常 1:枪锁故障 255:故障 默认0
                    //枪status:使用状态 0：空闲，1：使用中  2:插枪中 默认0
                    String gunStatus = redChargeDataService.getGunStatus(pile.getPileRtua(), elecGun.getGunNum());

                    logger.info("std心跳枪编号:{}，对应枪状态为:{},{}", elecGun.getGunNo(), elecGun.getStatus(), elecGun.getNormalStatus());
                    int value = 0;
                    if (hearBeat.getGunStatus().equals("03")) {//故障？
                        elecPileService.updateGunNormal(pile.getElecPileId(), elecGun.getGunNum(), 255);
                    } else if (hearBeat.getGunStatus().equals("04")) {//枪锁故障
                        elecPileService.updateGunNormal(pile.getElecPileId(), elecGun.getGunNum(), 1);
                    } else if (hearBeat.getGunStatus().equals("02")) {
                        value = -1;// 充电中
                        elecPileService.updateGunUsing(pile.getElecPileId(), elecGun.getElecGunId(), SocketConstant.GUN_USE);
                    } else if (hearBeat.getConnStatus().equals("01")) {
                        value = 1;// 插枪中
                        elecPileService.updateGunUsing(pile.getElecPileId(), elecGun.getElecGunId(), SocketConstant.GUN_PREPARE);
                    } else {
                        value = 0;// 空闲中
                        elecPileService.updateGunUsing(pile.getElecPileId(), elecGun.getElecGunId(), SocketConstant.GUN_LEISURE);

                        //插枪变空闲时，结算占用费
                        if (gunStatus.equals("1")) {
                            int i = elecStationService.selectOccupyStatusByelecStationId(pile.getElecStationId());
                            if (i == 0){
                                orderCostService.updateOccupyOrderinfoCost(pile.getElecPileId(),elecGun.getElecGunId());
                            }
                        }
                    }

                    //枪状态发生改变，推送至滴滴、万城、蔚来、粤易充 (互联互通)
                    if (gunStatus == null || Integer.valueOf(gunStatus) != value) {
                        notiyStationsStatus.notifyGunStatus(elecGun);
                    }

                    redChargeDataService.putGunStatus(pile.getPileRtua(), elecGun.getGunNum(), String.valueOf(value));
                }
            }

            //更新桩通讯地址
            //elecPileHostService.updateHostByElecPileId(pile.getElecPileId());

            //通过判断版本号是否一致,来判断远程升级;
            String version = hearBeatResult.getHearBeats().get(0).getVersion();
            elecPileService.updateVersion(pile.getElecPileId(), version);
        } catch (Exception e) {
            logger.error("hearBeat,对应的电桩ID为:" + hearBeatResult.getPileId(), e);
        }
    }


    @Override
    public ChargeReportRet chargeReport(ElecPile pile, TerminalMessage msg) {
        Result result = new ChargeReportResult();
        ChargeReportResult crr = result.getResult(msg.getData());
        crr.setPileId(pile.getElecPileId());

        try {
            ChargeReportRet fcrr = new ChargeReportRet(SocketConstant.STOP_NORMAL_0X0);
            // 获取订单号;
            String orderNum = crr.getOrderNum();
            fcrr.setOrderNum(orderNum);
            OrderInfo order = orderInfoService.selectByOrderNum(orderNum);

            // 如果订单不存在，则根据上报指令反向生成订单;
            if (order == null) {
                //先生成
                OrderInfo order1 = orderInfoService.addOrder(pile.getPileRtua(), crr.getGunNum(), orderNum);
                if (order1 == null) {
                    return fcrr;
                }
                //再查找
                order = orderInfoService.selectByOrderNum(orderNum);
                //广播启动成功的消息
                notifyStartChargeResult.notifyOrderStart(orderNum, SocketConstant.CON0);

            }

            //防止被平台停止的订单再产生数据，从而引起负数问题
            if ((WebConstant.CON2 + "").equals(order.getStatus())) {
                //平台停止
                fcrr.setStopType(SocketConstant.STOP_IS_ORDER_0XD);
                return fcrr;
            }

            MemberInfo memberInfo = memberInfoService.selectByPrimaryKey(order.getMemberId());
            fcrr.setOrderNum(order.getOrderNum());
            fcrr.setGunNum(crr.getGunNum());
            fcrr.setMemberId(memberInfo.getMemberId());
            fcrr.setPreSoc(memberInfo.getLimitSoc());
            fcrr.setElec(crr.getElec());

            //todo 防止同步拦截。待验证   多线程引起的问题，现已修复
            //if (redPileService.checkExpireGun(pile.getPileRtua(), crr.getGunNum(), 1500)) {
            //    logger.warn("std充电中异步并发拦截,丢弃报文，对应桩:{},订单号:{}", pile.getPileNo(), crr.getOrderNum());
            //    fcrr.setSoc(BigDecimal.ZERO);
            //    fcrr.setBatteryTemp(crr.getTemperatureHigh().intValue());
            //    return fcrr;
            //}

            //添加充电的开始soc，添加订单的vin码
            orderInfoService.updateOrderBySocOrVin(order.getOrderId(), crr.getSoc(), crr.getSvin());

            //ChargeReportResult转换为ChargeBalaceDto
            ChargeBalaceDto cbdto = dozerMapper.map(crr, ChargeBalaceDto.class);

            //保存到ycc中的hash值中
            redPileService.putPileToRedis(pile.getPileRtua(), cbdto);
            //保存到ycc中的hash值中
            redChargeDataService.putOrderNum(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), order.getOrderNum());
            //启动结果一直更新为成功
            redChargeDataService.putChargeResult(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), SocketConstant.STR_CON2);
            //redChargeDataService.putChargeResult(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), SocketConstant.STR_CON2);
            // 获取当前时间并存入redis中;
            redChargeDataService.putChargeReportTime(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), DateHelper.dataToString(new Date(), DateHelper.DATE_COMMON_FORMAT));
            //redChargeDataService.putChargeReportTime(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), DateHelper.dataToString(new Date(), DateHelper.DATE_COMMON_FORMAT));
            // 获取电压并存入redis中;
            redChargeDataService.putVol(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getVoltage());
            //redChargeDataService.putVol(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), crr.getVoltage());
            // 获取电流并存入redis中;
            redChargeDataService.putElec(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getElec());
            //redChargeDataService.putElec(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), crr.getElec());
            // 获取soc并存入redis中;
            redChargeDataService.putSoc(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getSoc());
            //redChargeDataService.putSoc(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), crr.getSoc());
            // 获取单体最高温度并存入redis中;
            redChargeDataService.putTemperatureHigh(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getTemperatureHigh());
            //redChargeDataService.putTemperatureHigh(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), crr.getTemperatureHigh());
            // 获取单体最底温度并存入redis中;
            redChargeDataService.putTemperatureLow(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getTemperatureLow());
            //redChargeDataService.putTemperatureLow(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), crr.getTemperatureLow());
            // 获取需求电压并存入redis中;
            redChargeDataService.putDemandVoltage(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getDemandVoltage());
            //redChargeDataService.putDemandVoltage(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), crr.getDemandVoltage());
            // 获取需求电流并存入redis中;
            redChargeDataService.putDemandElec(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getDemandElec());
            //redChargeDataService.putDemandElec(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), crr.getDemandElec());
            //获取电量并存入redis中;
            //BigDecimal lastPowerValue = redChargeDataService.getPower(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum());
            //redChargeDataService.putPower(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), crr.getPower());
            //赋值soc,最高电池温度
            fcrr.setSoc(crr.getSoc());
            fcrr.setBatteryTemp(crr.getTemperatureHigh().intValue());

            //保存订单开始时间的电价列表，每次都查缓存数据，不受数据库电价改动影响
            chargePriceHandler.putRedPricesHandler(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), pile.getElecStationId());
            //获取电价
            ElecStationPrice elecStationPrice = elecStationPriceService.selectRedValidElecStationPriceByDate(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), new Date());
            if (elecStationPrice == null) {
                //电价异常停止
                fcrr.setStopType(SocketConstant.STOP_ELEC_PRICE_EXCEPTION_0x5);
                return fcrr;
            }


            //todo 实时计算原价电量金额
            CalculateDto calculateDto = new CalculateDto();
            calculateDto.setElecPileId(pile.getElecPileId());
            calculateDto.setPileRtua(pile.getPileRtua());
            calculateDto.setElecStationPriceId(pile.getElecStationId());
            calculateDto.setGunNum(crr.getGunNum());
            calculateDto.setElecStationPriceId(elecStationPrice.getPriceId());
            calculateDto.setMobile(memberInfo.getMobile());
            calculateDto.setPower(crr.getPower());
            //calculateDto.setPowerValue(lastPowerValue);
            calculateDto.setOrderNum(order.getOrderNum());

            //添加实时电价
            calculateDto.setServicePrice(elecStationPrice.getServicePrice());
            calculateDto.setElecPrice(elecStationPrice.getElecPrice());

            CalcalateResultDto calcalateResultDto = chargeHandler.calculateAmount(calculateDto);

            /**获取个人或者企业余额**/
            BigDecimal account = memberInfoService.getAccountByChargeType(order.getOrderId());
            BigDecimal subAcount = account.subtract(calcalateResultDto.getTotalAmount());

            logger.info(this.getClass().getSimpleName() + " A5订单号:{},soc:{},电量:{},电流:{},电压:{},会员余额:{},基本电费:{},服务费:{},总金额:{},温度阈值:{}",
                    order.getOrderNum(), crr.getSoc(), crr.getPower(), crr.getElec(), crr.getVoltage(), account,
                    calcalateResultDto.getElecAmount(), calcalateResultDto.getServiceAmount(), calcalateResultDto.getTotalAmount(), crr.getTemperatureHigh());


            /**如果用户余额不足,后台自动结算**/
            BigDecimal stop_charge_account_limit = tenantSettingService.query_stop_charge_account_limit(memberInfo.getTenantCode());
            if (subAcount.compareTo(stop_charge_account_limit) != 1) {
                logger.warn("如果用户余额不足,后台自动结算,:{},:{},:{}", memberInfo.getMemberId(), order.getOrderNum(), stop_charge_account_limit);

                //余额不足停止
                fcrr.setStopType(SocketConstant.STOP_BALANCE_LOW_0x6);
                return fcrr;

                //共享充电，电量额度判断
            } else if (SocketConstant.STR_CON2.equals(order.getAccountType())) {
                logger.warn("如果用户已点击结算而订单未结算,后台自动结算,:{},:{},:{}", memberInfo.getMemberId(), order.getOrderNum(), stop_charge_account_limit);

                BigDecimal powerLimit = memberInfoService.selectPowerLimitByMemberId(order.getTenantCode(), order.getMemberId());
                powerLimit = powerLimit.subtract(crr.getPower());

                //共享余额的电量额度判断
                if (powerLimit.compareTo(new BigDecimal("1")) <= 0) {
                    logger.warn("如果用户共享额度不足,后台自动结算,:{},:{},:{}", memberInfo.getMemberId(), order.getOrderNum(), stop_charge_account_limit);

                    //余额不足停止
                    fcrr.setStopType(SocketConstant.STOP_BALANCE_LOW_0x6);
                    return fcrr;
                }
            } else if (HlhtOrderStatusEnum.HlhtOrderStatus5.equals(order.getHlhtOrderStatus())) {
                logger.warn("如果用户订单已挂单,后台自动结算,:{},:{}", memberInfo.getMemberId(), order.getOrderNum());
                //挂单停止
                fcrr.setStopType(SocketConstant.STOP_PENDING_ORDER_0X11);
                return fcrr;
            }

            //获取分时段差异电价
            ElecStationPrice bsp = chargePriceHandler.lastPriceHandler(calculateDto, elecStationPrice);
            if (bsp != null) {

                //按上次的实时充电量进行分段入库
                cbdto.setPower(calcalateResultDto.getLastPower()); //获取上一次充电轨迹的电量
                orderDetailService.saveByCharging(order.getOrderId(), cbdto, bsp, calcalateResultDto.getLastElecAmount(), calcalateResultDto.getLastTotalAmount());
                //redChargeDataService.putEpgPriceId(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), elecStationPrice.getPriceId());
                String jsonString = JSON.toJSONString(elecStationPrice);
                redChargeDataService.putOrderInfoCurrentPrice(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), jsonString);
            }


            ////获取电价时段的ID
            //String epgPriceValue = redChargeDataService.getEpgPriceId(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum());
            ////判断并保存分时段记录;
            //if (epgPriceValue == null) {
            //    redChargeDataService.putEpgPriceId(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), elecStationPrice.getPriceId().toString());
            //
            //    String jsonString = JSON.toJSONString(elecStationPrice);
            //    redChargeDataService.putOrderInfoCurrentPrice(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), jsonString);
            //    //redChargeDataService.putEpgPriceId(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), elecStationPrice.getPriceId().toString());
            //    } else if (epgPriceValue != null && (Long.valueOf(epgPriceValue).longValue() != elecStationPrice.getPriceId().longValue())) {
            //    //} else if (elecStationPriceStr != null) {
            //    /* bsp是保存上次充电的电费，服务费单价*/
            //    //ElecStationPrice bsp = JSON.parseObject(elecStationPriceStr, ElecStationPrice.class);
            //    //if (bsp.getPriceId().longValue() != elecStationPrice.getPriceId().longValue()) {
            //    //
            //    //}
            //    /* 保存各时段订单 bsp是保存上次充电的电费，服务费单价*/
            //    //ElecStationPrice bsp = elecStationPriceService.selectByPrimaryKey(Long.valueOf(epgPriceValue));
            //
            //    //按上次的实时充电量进行分段入库
            //    cbdto.setPower(calcalateResultDto.getLastPower()); //获取上一次充电轨迹的电量
            //    orderDetailService.saveByCharging(order.getOrderId(), cbdto, bsp, calcalateResultDto.getLastElecAmount(), calcalateResultDto.getLastTotalAmount());
            //    redChargeDataService.putEpgPriceId(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), elecStationPrice.getPriceId());
            //
            //}

            //异步保存充电过程
//            chargedProcessLogAssemble.assembleChargedProcessLog(ChargePhaseEnum.ON_CHARGEING, crr, order, calcalateResultDto.getElecAmount(), calcalateResultDto.getServiceAmount());

            return fcrr;
        } catch (Exception e) {
            logger.error("A5报文解析异常", e);
            return new ChargeReportRet(SocketConstant.CON0);
        }

    }

    @Override
    public ChargeControlRet readElecControl(ElecPile pile, TerminalMessage msg) {
        Result result = new ChargeControlResult();
        ChargeControlResult ccr = result.getResult(msg.getData());

        Integer chargeResult = WebConstant.CON1;

        OrderComment orderComment = orderCommentService.selectByOrderNum(ccr.getOrderNum());

        //        Long memberId = redMemberService.getMemberId(pile.getPileRtua(), ccr.getGunNum());
        logger.warn("充电指令结果数据：用户id:" + orderComment.getMemberId() + ",桩地址:" + pile.getPileRtua() + ",枪号：" + ccr.getGunNum());

        MemberInfo memberInfo = memberInfoService.selectByPrimaryKey(orderComment.getMemberId());

        if (ccr.getExecuteResult().endsWith(String.valueOf(SocketConstant.CON1))
                || ccr.getExecuteResult().endsWith(String.valueOf(SocketConstant.CON2))) {
            //开始
            handelStartElecResult(ccr, memberInfo, pile);
        } else {
            //停止
            chargeResult = handelStopElecResult(ccr, memberInfo, pile);
        }

        //保存充电过程
//        chargedProcessLogAssemble.assembleChargedProcessLog(ccr, orderComment);

        return new ChargeControlRet(chargeResult, ccr.getGunNum());
    }

    /**
     * 处理启动命令结果
     *
     * @param ccr
     * @param memberInfo
     * @param pile
     */
    private void handelStartElecResult(ChargeControlResult ccr, MemberInfo memberInfo, ElecPile pile) {

        String chargeResult = SocketConstant.CON2 + "";  //启动成功

        ElecGun gun = elecGunService.validGun(pile, ccr.getGunNum());

        //启动失败
        if (ccr.getExecuteResult().endsWith(String.valueOf(SocketConstant.CON2))) {

            // 将电桩对应的枪口变回可用状态
            elecPileService.updateGunUsing(pile.getElecPileId(), gun.getElecGunId(), SocketConstant.GUN_LEISURE);

            chargeResult = SocketConstant.CON3 + "";    //启动失败

            //广播启动失败的消息
            notifyStartChargeResult.notifyOrderStart(ccr.getOrderNum(), SocketConstant.CON1);
        }

        // 启动成功,充电操作成功生成订单、保存已存在的资源占用费记录
        else if (ccr.getExecuteResult().endsWith(String.valueOf(SocketConstant.CON1))) {
            try {
                orderInfoService.addOrder(pile.getPileRtua(), ccr.getGunNum(), ccr.getOrderNum());

                //广播启动成功的消息
                notifyStartChargeResult.notifyOrderStart(ccr.getOrderNum(), SocketConstant.CON0);
            } catch (Exception e) {
                logger.error("启动成功,充电操作成功生成订单，广播失败订单号:{},错误信息:{}", ccr.getOrderNum(), e);
                e.printStackTrace();
            }
        }

        //删除枪约束
        redChargeDataService.removeCheckPileTime(pile.getPileRtua(), gun.getGunNum(), "");

        //更新失败原因
        redChargeDataService.putChargeResult(pile.getPileRtua(), gun.getGunNum(), ccr.getOrderNum(), chargeResult);
        //更新失败原因
        //redChargeDataService.putChargeResult(pile.getPileRtua(), gun.getGunNum(), memberInfo.getMobile(), chargeResult);
    }

    /**
     * 处理停止充电确认帧
     * 回复成功就更新订单停止动作为手动停止,枪状态变了空闲状态，用户充电状态变为空闲，添加异常结算定时器（1分收不到充电记录就后自动结算），
     * 停止失败就只能手动停止
     *
     * @param ccr
     * @param memberInfo
     * @param pile
     */
    private Integer handelStopElecResult(ChargeControlResult ccr, MemberInfo memberInfo, ElecPile pile) {

        Integer chargeResult = SocketConstant.CON4;

        if (ccr.getExecuteResult().endsWith(String.valueOf(SocketConstant.CON3))) {

            logger.warn("handelStopElecResult将用户充电状态变了可用,订单号：{}" + ccr.getOrderNum());

            //0.发送指令成功  1.发送指令失败   2.启动成功    3.启动失败  4.停止成功  5.停止失败
            redChargeDataService.putChargeResult(pile.getPileRtua(), ccr.getGunNum(),
                    ccr.getOrderNum(), chargeResult);
            //redChargeDataService.putChargeResult(pile.getPileRtua(), ccr.getGunNum(),
            //        memberInfo.getMobile(), chargeResult);
        } else {

            chargeResult = SocketConstant.CON5;

            logger.error("handelStopElecResult停止失败！订单号:{}" + ccr.getOrderNum());

            //0.发送指令成功  1.发送指令失败   2.启动成功    3.启动失败  4.停止成功  5.停止失败
            //redChargeDataService.putChargeResult(pile.getPileRtua(), ccr.getGunNum(),
            //        memberInfo.getMobile(), chargeResult);
            redChargeDataService.putChargeResult(pile.getPileRtua(), ccr.getGunNum(),
                    ccr.getOrderNum(), chargeResult);

            //OrderInfo orderInfo = orderInfoService.selectByOrderNum(ccr.getOrderNum());
            //StopChargeReq stopChargeReq = new StopChargeReq();
            //stopChargeReq.setElecPileId(pile.getElecPileId());
            //stopChargeReq.setOrderNum(orderInfo.getOrderNum());
            //stopChargeReq.setGunNum(ccr.getGunNum());
            //stopChargeReq.setMemberId(memberInfo.getMemberId());
            //stopChargeReq.setStopType(SocketConstant.STOP_NORMAL_0X0);
            //String msg0 = JSON.toJSONString(stopChargeReq);
            //mqProducer.sendDelay(mqCommandConfig.getCONTROLL_8E_DELAY_STOP(), msg0, 1000);
        }


        return chargeResult;
    }

    @Override
    public ChargeBalaceRet chargeBalace(ElecPile pile, TerminalMessage msg) {
        Result result = new ChargeBalaceResult();
        ChargeBalaceResult cbr = result.getResult(msg.getData());
        cbr.setPileId(pile.getElecPileId());
        try {
            logger.warn("收到A6指令做结算处理soc:{},orderNum:{} " + cbr.getSoc(), cbr.getOrderNum());
            OrderInfo order = orderInfoService.selectByOrderNum(cbr.getOrderNum());

            if (order == null) {
                return new ChargeBalaceRet();
            }
            //接收补推的订单
            if ("2".equals(order.getStatus())) {
                //接收补推的结算数据
                OrderDelayPush orderDelayPush = orderDelayPushService.selectOrderNum(cbr.getOrderNum());
                if (orderDelayPush == null) {
                    //ChargeReportResult转换为ChargeBalaceDto
                    ChargeBalaceDto cbdto = dozerMapper.map(cbr, ChargeBalaceDto.class);
                    orderDelayPushService.addOrderDelayPush(cbdto, pile.getElecPileId(), order.getOrderId());
                }
                return new ChargeBalaceRet();
            }

            //添加2秒锁，防止重复结算
            String synOrderNumKey = SynEnum.SYN_ORDERCOST_ORDERNUM.getCode() + order.getOrderNum();

            //添加2秒锁，同一个用户结算延迟结算
            String synMemberIdKey = SynEnum.SYN_ORDERCOST_ORDERNUM.getCode() + order.getMemberId();

            if (synExcution.synOrderNum(synOrderNumKey, 1000L) == 0) {
                logger.warn("chargeBalace.A6.1秒内用户重复结算，将自动返回，对应订单号:" + order.getOrderNum());
                return new ChargeBalaceRet();
            }

            if (!redisService.setIfAbsent(synMemberIdKey, 1, 1000L)) {

                String dataJson = JSON.toJSONString(msg);

                if (System.currentTimeMillis() - msg.getCurrentTimeMillis() > 600 * 1000) {
                    mqProducer.sendDelay(mqCommandConfig.getCONTROLL_A6(), dataJson, 600 * 1000);
                } else {
                    mqProducer.sendDelay(mqCommandConfig.getCONTROLL_A6(), dataJson, 2000);
                }

                logger.warn("chargeBalace.A6.1秒内用户结算延迟，对应订单号:" + order.getOrderNum());
                return new ChargeBalaceRet();
            }

            //保存上报的总电量
            //            pilePowerService.savePilePower(cbr.getPowerA(), cbr.getPowerB(), order);
            MemberInfo memberInfo = memberInfoService.selectByPrimaryKey(order.getMemberId());

            // 获取当前时间并存入redis中;
            redChargeDataService.putChargeReportTime(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), DateHelper.dataToString(new Date(), DateHelper.DATE_COMMON_FORMAT));
            //redChargeDataService.putChargeReportTime(pile.getPileRtua(), cbr.getGunNum(), memberInfo.getMobile(), DateHelper.dataToString(new Date(), DateHelper.DATE_COMMON_FORMAT));
            // 获取电压并存入redis中;
            redChargeDataService.putVol(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), cbr.getVoltage());
            //redChargeDataService.putVol(pile.getPileRtua(), cbr.getGunNum(), memberInfo.getMobile(), cbr.getVoltage());
            // 获取电流并存入redis中;
            redChargeDataService.putElec(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), cbr.getElec());
            //redChargeDataService.putElec(pile.getPileRtua(), cbr.getGunNum(), memberInfo.getMobile(), cbr.getElec());
            // 获取soc并存入redis中;
            redChargeDataService.putSoc(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), cbr.getSoc());
            //redChargeDataService.putSoc(pile.getPileRtua(), cbr.getGunNum(), memberInfo.getMobile(), cbr.getSoc());
            //获取桩停止原因并存入redis中
            redChargeDataService.putPileStopMode(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), cbr.getElecPileStopReason());
            //redChargeDataService.putPileStopMode(pile.getPileRtua(), cbr.getGunNum(), memberInfo.getMobile(), cbr.getElecPileStopReason());
            //获取电量并存入redis中;
            //BigDecimal powerValue = redChargeDataService.getPower(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum());

            //保存订单开始时间的电价列表，每次都查缓存数据，不受数据库电价改动影响
            chargePriceHandler.putRedPricesHandler(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), pile.getElecStationId());
            //获取电价
            ElecStationPrice elecStationPrice = elecStationPriceService.selectRedValidElecStationPriceByDate(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), new Date());
            if (elecStationPrice == null) {
                // 订单结算 默认停止原因为手动停止;
                orderCostService.updateOrderCost(order.getOrderNum(), SocketConstant.STOP_NORMAL_0X0);
                ///推送订单停止状态
                notifyStopChargeResult.notifyOrderStop(order.getOrderNum(), SocketConstant.CON0, SocketConstant.CON0, 0);

                logger.error("收到A6,该时段没有对应电价错误,无法计算电价！！！桩：{},订单号:{}" + pile.getPileRtua(), order.getOrderNum());
                return new ChargeBalaceRet(WebConstant.CON1 + "", order.getOrderId());
            }

            //todo 实时计算原价电量金额
            CalculateDto calculateDto = new CalculateDto();
            calculateDto.setElecPileId(pile.getElecPileId());
            calculateDto.setPileRtua(pile.getPileRtua());
            calculateDto.setGunNum(cbr.getGunNum());
            calculateDto.setElecStationPriceId(elecStationPrice.getPriceId());
            calculateDto.setMobile(memberInfo.getMobile());
            calculateDto.setPower(cbr.getPower());
            calculateDto.setOrderNum(order.getOrderNum());
            //添加实时电价
            calculateDto.setServicePrice(elecStationPrice.getServicePrice());
            calculateDto.setElecPrice(elecStationPrice.getElecPrice());

            CalcalateResultDto calcalateResultDto = chargeHandler.calculateAmount(calculateDto);

            //获取电价时段的ID
            //String epgPriceValue = redChargeDataService.getEpgPriceId(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum());
            //判断并保存分时段记录;
            //if (elecStationPrice == null) {
            //    redChargeDataService.putEpgPriceId(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), elecStationPrice.getPriceId().toString());
            //    //redChargeDataService.putEpgPriceId(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), elecStationPrice.getPriceId().toString());
            //} else if (epgPriceValue != null && (Long.valueOf(epgPriceValue).longValue() != elecStationPrice.getPriceId().longValue())) {
            //    /* 保存各时段订单 bsp是保存上次充电的电费，服务费单价*/
            //    ElecStationPrice bsp = elecStationPriceService.selectByPrimaryKey(Long.valueOf(epgPriceValue));
            //
            //    //按上次的实时充电量进行分段入库
            //    cbdto.setPower(calcalateResultDto.getLastPower()); //获取上一次充电轨迹的电量
            //    orderDetailService.saveByCharging(order.getOrderId(), cbdto, bsp, calcalateResultDto.getLastElecAmount(), calcalateResultDto.getLastTotalAmount());
            //    redChargeDataService.putEpgPriceId(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), elecStationPrice.getPriceId());
            //    //redChargeDataService.putEpgPriceId(pile.getPileRtua(), crr.getGunNum(), memberInfo.getMobile(), elecStationPrice.getPriceId());
            //}

            ChargeBalaceDto cbdto = dozerMapper.map(cbr, ChargeBalaceDto.class);
            //获取分时段差异电价
            ElecStationPrice bsp = chargePriceHandler.lastPriceHandler(calculateDto, elecStationPrice);
            if (bsp != null) {

                //按上次的实时充电量进行分段入库
                cbdto.setPower(calcalateResultDto.getLastPower()); //获取上一次充电轨迹的电量
                orderDetailService.saveByCharging(order.getOrderId(), cbdto, bsp, calcalateResultDto.getLastElecAmount(), calcalateResultDto.getLastTotalAmount());
                //redChargeDataService.putEpgPriceId(pile.getPileRtua(), crr.getGunNum(), order.getOrderNum(), elecStationPrice.getPriceId());
                String jsonString = JSON.toJSONString(elecStationPrice);
                redChargeDataService.putOrderInfoCurrentPrice(pile.getPileRtua(), cbr.getGunNum(), order.getOrderNum(), jsonString);
            }

            //停止方式
            String elecPileStopReasonResult = ElecPileStopReasonEnum.getElecPileStopReasonResult(cbr.getElecPileStopReason());
            logger.info(this.getClass().getSimpleName() + "A6订单号:{},soc:{},电量:{},余额:{},停止原因:{},最高温度:{}", order.getOrderNum(),
                    cbr.getSoc(), cbr.getPower(), memberInfo.getJoinMemberAccount().getAccount(), elecPileStopReasonResult);

            // 订单结算 默认停止原因为手动停止;
            orderCostService.updateOrderCost(order.getOrderNum(), SocketConstant.STOP_NORMAL_0X0);
            //推送订单停止状态
            notifyStopChargeResult.notifyOrderStop(order.getOrderNum(), SocketConstant.CON0, SocketConstant.CON0, 0);
//            chargedProcessLogAssemble.assembleChargedProcessLog(ChargePhaseEnum.SETTLED, cbr, order, calcalateResultDto.getElecAmount(), calcalateResultDto.getServiceAmount());

            //删锁
            redisService.remove(synOrderNumKey);
            redisService.remove(synMemberIdKey);

            return new ChargeBalaceRet(WebConstant.CON1 + "", order.getOrderId());
        } catch (Exception e) {
            logger.error("收到A6指令做结算处理异常:" + cbr.getOrderNum(), e);
            return new ChargeBalaceRet();
        }
    }

    @Override
    public Integer readLimitPower(ElecPile pile, TerminalMessage msg) {
        ElecPileLimitPowerResult result = new ElecPileLimitPowerResult(msg.getData(), null);

        logger.info("收到C6指令readLimitPower:" + result.toString());
        if (result != null && "00".equals(result.getResult())) {
            //todo mq发送告知限制成功
            return 0;
        } else {

            return null;
        }
    }

    @Override
    public void readPower(ElecPile pile, TerminalMessage msg) {
        ElecPilePower elecPilePower = elecPilePowerService.selectByPrimaryKey(pile.getElecPileId());
        ElecPilePowerResult result = new ElecPilePowerResult(msg.getData(), null);
        if (elecPilePower == null) {
            elecPilePower = new ElecPilePower();
        }
        BeanUtils.copyProperties(result, elecPilePower);
        elecPilePower.setLastUpdatedTime(new Date());
        if (elecPilePower.getElecPileId() == null) {
            elecPilePower.setElecPileId(pile.getElecPileId());
            elecPilePower.setCreatedTime(elecPilePower.getLastUpdatedTime());
            elecPilePower.setElecStationId(pile.getElecStationId());
            elecPilePower.setTenantCode(pile.getTenantCode());
            elecPilePowerService.insertSelective(elecPilePower);
        } else {
            elecPilePowerService.updateByPrimaryKeySelective(elecPilePower);
        }
        logger.info("收到C5指令录入实时数据:" + JSON.toJSONString(elecPilePower));

    }
}
